﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Xml.Linq;
using System.Reflection;

namespace GameStateManagement.GameHelper
{
    class Info : Attribute
    {
        public string XName { get; set; }
        public Info(string Name)
        {
            XName = Name;
        }
    }

    public sealed class GameSettings
    {
        public ScreenManager ScreenManager { get; set; }
        private bool _SoundEnable;
        private bool _AudioEnable;
        private bool _FullScreen;
        private bool _Notiy = true;
        private bool _AutoSave;
        private int _LastLevel;

        [Info("AutoSave")]
        public bool AutoSave { get { return this._AutoSave; } set { this._AutoSave = value; if (_Notiy) this.Store.Notify(); } }

        [Info("LastLevel")]
        public int LastLevel { get { return this._LastLevel; } set { this._LastLevel = value; if (_Notiy) this.Store.Notify(); } }


        [Info("SoundEnable")]
        public bool SoundEnable { get { return this._SoundEnable; } set { this._SoundEnable = value; if (_Notiy) this.Store.Notify(); } }

        [Info("AudioEnable")]
        public bool AudioEnable { get { return this._AudioEnable; } set { this._AudioEnable = value; if (_Notiy)this.Store.Notify(); } }

        [Info("FullScreen")]
        public bool IsFullScreen { get { return this._FullScreen; } set { this._FullScreen = value; if (_Notiy)this.Store.Notify(); } }


        public Storing Store { get; set; }


        public void NotifyWhenChange(bool v)
        {
            this._Notiy = v;
        }

        public GameSettings Load()
        {       
            Store.Load();
            return this;
        }

        public GameSettings Save()
        {
            this.Store.Save();
            return this;
        }

        GameSettings()
        {
            Store = new Storing() { Settings = this };           
        }


        #region Singleton

        public static GameSettings Instance
        {
            get
            {
                return Nested.instance;
            }
        }

        class Nested
        {
            static Nested()
            {
            }

            internal static readonly GameSettings instance = new GameSettings();
        }
        #endregion
    }

    public class Storing
    {
        public Storing()
        {
            XML = XElement.Load(ConfigurationManager.AppSettings["settings"]);
        }
        public GameSettings Settings { get; set; }
        protected XElement XML { get; set; }

        public Storing Notify()
        {
            PropertyInfo[] props = typeof(GameSettings).GetProperties();
            foreach (var item in props)
            {
                foreach (var attr in item.GetCustomAttributes(false))
                {
                    Info i = attr as Info;
                    if (i != null)
                    {
                        XML.Element("View").SetElementValue(i.XName, item.GetValue(this.Settings, null));
                    }
                } 
            }
            return this;
        }

        public Storing Load()
        {
            PropertyInfo[] props = typeof(GameSettings).GetProperties();

            var view = XML.Element("View");
            this.Settings.NotifyWhenChange(false);
            foreach (var x in view.Elements())
            {
                var pro = props.FirstOrDefault(s => 
                    s.GetCustomAttributes(typeof(Info), false)
                    .FirstOrDefault(f => ((Info)f).XName == x.Name)
                != null);
                if (pro != null)
                {     
                    object o = x.Export(pro);
                    pro.SetValue(this.Settings,  o, null);
                }
            }
            this.Settings.NotifyWhenChange(true);
            return this.Apply();
        }

        
        public Storing Apply()
        {            
            return this;
        }

        public GameSettings Save()
        {
            XML.Save(ConfigurationManager.AppSettings["settings"]);
            return this.Settings;
        }
    }

    public static class Propertiess
    {
        public static object Export(this XElement x,  PropertyInfo p)
        {
            if (p.PropertyType == typeof(Boolean))
                return Boolean.Parse(x.Value);

            if (p.PropertyType == typeof(Int32))
                return Int32.Parse(x.Value);

            if (p.PropertyType == typeof(String))
                return x.Value;

            if (p.PropertyType == typeof(float))
                return float.Parse(x.Value);
            
            return x.Value;
        }
    }


}
